package cc.siyecao.fastdfs.command.tracker;


import cc.siyecao.fastdfs.model.RecvPackageInfo;
import cc.siyecao.fastdfs.model.StorageInfo;
import cc.siyecao.fastdfs.protocol.ProtocolConstants;
import cc.siyecao.fastdfs.util.BytesUtil;
import cc.siyecao.fastdfs.util.ProtocolUtil;

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

/**
 * 获取存储节点命令
 *
 * @author lyt
 */
public class GetStoreStoragesCommand extends FdfsTrackerCommand<List<StorageInfo>> {
    public GetStoreStoragesCommand() {
    }

    public GetStoreStoragesCommand(String groupName) {
        this.groupName = groupName;
    }

    @Override
    protected void send(OutputStream out, Charset charset) throws Exception {
        byte[] header;
        String ipAddr;
        int port;
        byte cmd;
        int outLen;
        if (groupName == null || groupName.length() == 0) {
            cmd = TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL;
            outLen = 0;
        } else {
            cmd = TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL;
            outLen = ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN;
        }
        header = ProtocolUtil.packHeader( cmd, outLen, (byte) 0 );
        out.write( header );

        if (groupName != null && groupName.length() > 0) {
            byte[] bGroupName;
            byte[] bs;
            int groupLen;

            bs = groupName.getBytes( charset );
            bGroupName = new byte[ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN];

            if (bs.length <= ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN) {
                groupLen = bs.length;
            } else {
                groupLen = ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN;
            }
            Arrays.fill( bGroupName, (byte) 0 );
            System.arraycopy( bs, 0, bGroupName, 0, groupLen );
            out.write( bGroupName );
        }
    }

    @Override
    protected List<StorageInfo> receive(InputStream in, Charset charset) throws Exception {
        RecvPackageInfo pkgInfo = ProtocolUtil.recvPackage( in, TRACKER_PROTO_CMD_RESP, -1 );
        this.errno = pkgInfo.errno;
        if (pkgInfo.errno != 0) {
            return null;
        }

        if (pkgInfo.body.length < ProtocolConstants.TRACKER_QUERY_STORAGE_STORE_BODY_LEN) {
            this.errno = ProtocolConstants.ERR_NO_EINVAL;
            return null;
        }

        int ipPortLen = pkgInfo.body.length - (ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN + 1);
        final int recordLength = ProtocolConstants.FDFS_IPADDR_SIZE - 1 + ProtocolConstants.FDFS_PROTO_PKG_LEN_SIZE;

        if (ipPortLen % recordLength != 0) {
            this.errno = ProtocolConstants.ERR_NO_EINVAL;
            return null;
        }

        int serverCount = ipPortLen / recordLength;
        if (serverCount > 16) {
            this.errno = ProtocolConstants.ERR_NO_ENOSPC;
            return null;
        }

        StorageInfo[] results = new StorageInfo[serverCount];
        byte storePath = pkgInfo.body[pkgInfo.body.length - 1];
        int offset = ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN;

        for (int i = 0; i < serverCount; i++) {
            String ipAddr = new String( pkgInfo.body, offset, ProtocolConstants.FDFS_IPADDR_SIZE - 1 ).trim();
            offset += ProtocolConstants.FDFS_IPADDR_SIZE - 1;

            int port = (int) BytesUtil.buff2long( pkgInfo.body, offset );
            offset += ProtocolConstants.FDFS_PROTO_PKG_LEN_SIZE;

            results[i] = new StorageInfo( ipAddr, port, storePath );
        }

        return Arrays.asList( results );
    }
}
